package session.TX;

import Helper.TTAHelper.Helper_IPCluster;
import entity.Outlet;
import entity.OutletReservation;
import entity.Users;
import entity.tta.OutletDataModel;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Random;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 *
 * @author Lu Xiaodi
 */
@Stateless
public class ItineraryPlannerSB implements ItineraryPlannerSBRemote {

    @PersistenceContext
    EntityManager em;

    public List<Helper_IPCluster> recommendOutletId(Long userId) {
        // get ageGroupsIdx and countriesIdx
        Users user = em.find(Users.class, userId);
        if (user == null) {
            // throw usernotfound exception
            return null;
        }
        int ageGroupsIdx = this.computeAgeGroupsIdx(user);
        int countriesIdx = this.computeCountriesIdx(user);

        // get helper_cluster for all outlet data models (stored in List clusters)
        Query query = em.createQuery("SELECT o FROM OutletDataModel o");
        List<OutletDataModel> allOutletDataModels = query.getResultList();
        List<Helper_IPCluster> allClusters = new ArrayList<Helper_IPCluster>();
        for (OutletDataModel o : allOutletDataModels) {
            allClusters.add(new Helper_IPCluster(o.getOutletId(), o.getCluster()[countriesIdx][ageGroupsIdx]));
        }
        allOutletDataModels = null;

        List<Helper_IPCluster> top50Cluster = this.getTop50(allClusters);

        return top50Cluster;
    }

    private int computeAge(Users user) {
        Calendar birthdate = Calendar.getInstance();
        birthdate.setTime(user.getBirthDate());
        Calendar systemTime = Calendar.getInstance();
        systemTime.setTime(new Date());
        int age = systemTime.get(Calendar.YEAR) - birthdate.get(Calendar.YEAR);
        return age;
    }

    /**
     * List of countries:
     * 1. Southeast Asia: Brunei Darussalam, Indonesia, Malaysia, Myanmar, Philippines, Thailand, Vietnam, Other Countries in Southeast Asia
     * 2. North Asia: P R China, Taiwan, Hong Kong SAR, Japan, South Koria, Other Countries in North Asia
     * 3. South Asia: Bangladesh, India, Nepal, Pakistan, Sri Lanka, Other Countries in South Asia
     * 4. West Asia: Iran, Israel, Kuwait, Saudi Arabia, United Arab Emirates, Other Countries in West Asia
     * 5. Europe: Austria, Belgium & Luxembourg, Denmark, Finland, France, Germany, Greece, Italy, Netherlands,
    Norway, Porland, Rep of Ireland, Russian Federation, Spain, Sweden, Switzerland, Turkey, UK, 
    Other Countries in Eastern Europe, Other Countries in Western Europe
     * 6. Occeania: Australia, New Zealand, Other Countries in Oceania
     * 7. Africa: Egypt, Mauritius, South Africa (Rep of), Other Countries in Africa
     * 8. Americas: Canada, USA, other countries in Americas
     */
    private int computeCountriesIdx(Users user) {
        String country = user.getCountry();
        OutletDataModel model = new OutletDataModel();
        String[] countries = model.getCountriesArray();
        for (int i = 0; i < countries.length; i++) {
            if (countries[i].trim().equalsIgnoreCase(country)) {
                return i;
            }
        }
        return -1;
    }

    private int computeAgeGroupsIdx(Users user) {
        int age = this.computeAge(user);
        OutletDataModel model = new OutletDataModel();
        String[] ageGroups = model.getAgeGroupsArray();

        for (int i = 0; i < ageGroups.length; i++) {
            String[] ageBoundaries = ageGroups[i].split("-");
            Integer minAge = Integer.parseInt(ageBoundaries[0].trim());
            Integer maxAge = Integer.parseInt(ageBoundaries[1].trim());
            if (minAge <= age && age <= maxAge) {
                return i;
            }
        }
        return -1;
    }

    private List<Helper_IPCluster> getTop50(List<Helper_IPCluster> inputCluster) {
        List<Helper_IPCluster> returnList = new ArrayList<Helper_IPCluster>();
        //initialize returnList
        for (int i = 0; i < 50; i++) {
            returnList.add(new Helper_IPCluster(null, new Long(0)));
        }
        //populate returnList
        for (int i = 0; i < inputCluster.size(); i++) {
            Helper_IPCluster aCluster = inputCluster.get(i);
            for (int j = 0; j < returnList.size(); j++) {
                if (returnList.get(j).getPopularity() <= aCluster.getPopularity()) {
                    returnList.add(j, aCluster);
                    returnList.remove(returnList.size() - 1);
                    break;
                }
            }
        }
        
        //finalize returnList, remove dummy elements
        for (int i = 0 ; i<50; i++){
            if (returnList.get(i).getPopularity().longValue()==0){
                for (int j=i; j<50; j++){
                    //remove the last element
                    returnList.remove(returnList.size()-1);
                }
                break;
            }
        }
        //return result
        return returnList;
    }

    //==========================================================================
    // Below are testing methods
    //==========================================================================
    
    public void populateOutletReservation(){
        Query query = em.createQuery("SELECT u FROM Users u");
        List<Users> users = query.getResultList();
        Query outletQuery = em.createQuery("SELECT o FROM Outlet o");
        List<Outlet> outlets = outletQuery.getResultList();
        
        Random rm = new Random();
        int numReservations;
        int date;
        int month;
        int outletIdx;
        for (Users u: users){
            numReservations = rm.nextInt(20);
            for (int i = 0 ; i < numReservations; i++){
                outletIdx = rm.nextInt(4);
                Outlet o = outlets.get(outletIdx);
                date = rm.nextInt(27)+1;
                month = rm.nextInt(11); 
                Calendar c = Calendar.getInstance();
                c.set(2011, month, date);
                OutletReservation or = new OutletReservation();
                or.setCustomer(u);
                or.setCustomerShowUp(rm.nextBoolean());
                or.setOutlet(o);
                or.setTimeslot(c);
                u.addReservation(or);
                o.addReservations(or);
                em.persist(u);
                em.persist(o);
                em.persist(or);
            }
        }
    }
    
    public void createUser_Test(String email, String country, int birthYear) {
        Users user = new Users();
        user.setEmail(email);
        user.setCountry(country);
        Calendar c = Calendar.getInstance();
        c.set(birthYear, 1, 1);
        user.setBirthDate(c.getTime());
        em.persist(user);
    }

    public List<String> printUser_Test() {
        Query query = em.createQuery("SELECT u FROM Users u");
        List<Users> usersList = query.getResultList();
        List<String> returnList = new ArrayList<String>();
        for (Users u : usersList) {
            returnList.add("UserId:" + u.getId() + "; email:" + u.getEmail()
                    + "; country:" + u.getCountry() + "; birthdate:" + u.getBirthDate());
        }
        return returnList;
    }

    public List<Integer> getCountryAgeIdx(Long cId) {
        Users user = em.find(Users.class, cId);
        Integer countryIdx = this.computeCountriesIdx(user);
        Integer age = this.computeAge(user);
        Integer ageIdx = this.computeAgeGroupsIdx(user);
        List<Integer> returnList = new ArrayList<Integer>();
        returnList.add(countryIdx);
        returnList.add(age);
        returnList.add(ageIdx);
        return returnList;
    }

    public void addNewOutletDataModel_Test(Long outletId) {
        OutletDataModel od = new OutletDataModel();
        od.setOutletId(outletId);
        em.persist(od);
    }

    public void removeNewOutletDataModel_Test() {
        Query query = em.createQuery("SELECT d FROM OutletDataModel d WHERE d.outletId >= 100000 AND d.outletId < 100021");
        List<OutletDataModel> dataModels = query.getResultList();
        for (OutletDataModel aModel : dataModels) {
            em.remove(aModel);
        }
    }

    public List<String> printDataModelByUser(String customerEmail) {
        Query custQuery = em.createQuery("SELECT c FROM Users c WHERE c.email= :email");
        custQuery.setParameter("email", customerEmail);
        List<Users> users = custQuery.getResultList();
        Users selectedUser = users.get(0);

        Query query = em.createQuery("SELECT d FROM OutletDataModel d WHERE d.outletId >= 100000 AND d.outletId < 100021");
        List<OutletDataModel> dataModels = query.getResultList();
        if (dataModels == null || dataModels.isEmpty()) {
            return null;
        }

        int ageIdx = this.computeAgeGroupsIdx(selectedUser);
        int countryIdx = this.computeCountriesIdx(selectedUser);

        List<String> returnList = new ArrayList<String>();

        for (int i = 0; i < 20; i++) {
            OutletDataModel aDataModel = dataModels.get(i);
            returnList.add("DataModelId:" + aDataModel.getId() + "; OutletId:" + aDataModel.getOutletId()
                    + "; popularity:" + aDataModel.getCluster()[countryIdx][ageIdx]);
        }
        return returnList;
    }

    public void updateOutletDataModel_Test(String customerEmail) {
        Query custQuery = em.createQuery("SELECT c FROM Users c WHERE c.email= :email");
        custQuery.setParameter("email", customerEmail);
        List<Users> users = custQuery.getResultList();
        Users selectedUser = users.get(0);

        Query query = em.createQuery("SELECT d FROM OutletDataModel d WHERE d.outletId >= 100000 AND d.outletId < 100021");
        List<OutletDataModel> dataModels = query.getResultList();

        int ageIdx = this.computeAgeGroupsIdx(selectedUser);
        int countryIdx = this.computeCountriesIdx(selectedUser);

        for (int i = 0; i < 20; i++) {
            OutletDataModel aDataModel = dataModels.get(i);
            aDataModel.getCluster()[countryIdx][ageIdx] = new Long(i);
            em.persist(aDataModel);
        }
    }
    //==========================================================================
    // Above are testing methods
    //==========================================================================
}
